package service

import (
	"context"
	v1 "gin-vben-admin/api/v1"
	"gin-vben-admin/api/v1/errcode"
	"gin-vben-admin/internal/constant"
	"gin-vben-admin/internal/model"
	"gin-vben-admin/internal/repository"
	"golang.org/x/crypto/bcrypt"
)

type SysUserService interface {
	GetPageList(ctx context.Context, req *v1.SysUserListReq) (total int64, list []*model.SysUser, err error)
	Create(ctx context.Context, req *v1.SysUserCreateReq) error
	Update(ctx context.Context, req *v1.SysUserUpdateReq) error
	Detail(ctx context.Context, uid int64) (user *model.SysUser, err error)
	Delete(ctx context.Context, uid int64) (err error)
	EditStatus(ctx context.Context, uid int64, status int) (err error)
	ResetPassword(ctx context.Context, uid int64, req *v1.SysUserResetPwdReq) (err error)
}

func NewSysUserService(service *Service, userRepo repository.SysUserRepository) SysUserService {
	return &sysUserService{
		userRepo: userRepo,
		Service:  service,
	}
}

type sysUserService struct {
	userRepo repository.SysUserRepository
	*Service
}

func (s *sysUserService) GetPageList(ctx context.Context, req *v1.SysUserListReq) (total int64, list []*model.SysUser, err error) {
	return s.userRepo.PageList(ctx, req, "Role", "Dept")
}

func (s *sysUserService) Create(ctx context.Context, req *v1.SysUserCreateReq) error {
	m := model.SysUser{}
	m.Username = req.Username
	//m.Password = req.Password
	m.NickName = req.NickName
	if req.NickName == "" {
		m.NickName = m.Username
	}
	m.Avatar = req.Avatar
	m.Phone = req.Phone
	m.Email = req.Email
	m.RoleId = req.RoleId
	m.Sex = req.Sex
	m.DeptId = req.DeptId
	m.Status = req.Status
	m.Remark = req.Remark
	m.CreateBy = req.AuthId
	m.UpdateBy = req.AuthId

	var user *model.SysUser
	var err error
	if user, err = s.userRepo.GetByUsername(ctx, m.Username); err != nil {
		return err
	}
	if user != nil && user.UID > 0 {
		return errcode.ErrBadRequestParams.New("该用户名已经存在")
	}
	if m.Email != "" {
		if user, err = s.userRepo.GetByEmail(ctx, m.Email); err != nil {
			return err
		}
		if user != nil && user.UID > 0 {
			return errcode.ErrBadRequestParams.New("该邮箱已经存在")
		}
	}
	if m.Phone != "" {
		if user, err = s.userRepo.GetByPhone(ctx, m.Phone); err != nil {
			return err
		}
		if user != nil && user.UID > 0 {
			return errcode.ErrBadRequestParams.New("该邮箱已经存在")
		}
	}
	if m.Password, err = bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost); err != nil {
		return err
	}
	return s.userRepo.Create(ctx, &m)
}

func (s *sysUserService) Update(ctx context.Context, req *v1.SysUserUpdateReq) error {
	m, err := s.userRepo.GetByID(ctx, req.UID)
	if err != nil {
		return err
	}
	m.NickName = req.NickName
	if req.NickName == "" {
		m.NickName = m.Username
	}
	m.Avatar = req.Avatar
	m.Phone = req.Phone
	m.Email = req.Email
	m.RoleId = req.RoleId
	m.Sex = req.Sex
	m.DeptId = req.DeptId
	m.Status = req.Status
	m.Remark = req.Remark
	m.UpdateBy = req.AuthId
	var user *model.SysUser
	if m.Email != "" {
		if user, err = s.userRepo.GetByEmail(ctx, m.Email, m.UID); err != nil {
			return err
		}
		if user != nil && user.UID > 0 {
			return errcode.ErrBadRequestParams.New("该邮箱已经存在")
		}
	}
	if m.Phone != "" {
		if user, err = s.userRepo.GetByPhone(ctx, m.Phone, m.UID); err != nil {
			return err
		}
		if user != nil && user.UID > 0 {
			return errcode.ErrBadRequestParams.New("该邮箱已经存在")
		}
	}
	updateFields := []string{"nick_name", "avatar", "phone", "email", "role_id", "sex", "dept_id", "status", "remark", "update_by"}
	if req.Password != "" {
		if m.Password, err = bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost); err != nil {
			return err
		}
		updateFields = append(updateFields, "password")
	}
	return s.userRepo.Update(ctx, m, updateFields...)
}

// Detail 用户详情
func (s *sysUserService) Detail(ctx context.Context, uid int64) (user *model.SysUser, err error) {
	if uid == 0 {
		return nil, errcode.ErrBadRequest
	}
	return s.userRepo.GetByID(ctx, uid)
}

// Delete 删除用户
func (s *sysUserService) Delete(ctx context.Context, uid int64) (err error) {
	if uid == 0 || uid == constant.SuperAdmin {
		return errcode.ErrBadRequest
	}
	return s.userRepo.Delete(ctx, uid)
}

// EditStatus 更新用户状态
func (s *sysUserService) EditStatus(ctx context.Context, uid int64, status int) (err error) {
	if uid == 0 {
		return errcode.ErrBadRequest
	}
	user, err := s.userRepo.GetByID(ctx, uid)
	if err != nil {
		return err
	}
	if user.Status == constant.Status(status) {
		return errcode.ErrBadRequest.New("当前状态操作错误")
	}
	user.Status = constant.Status(status)
	return s.userRepo.Update(ctx, user, "status")
}

// ResetPassword 重置用户密码为默认密码
func (s *sysUserService) ResetPassword(ctx context.Context, uid int64, req *v1.SysUserResetPwdReq) (err error) {
	if uid == 0 {
		return errcode.ErrBadRequest
	}
	user, err := s.userRepo.GetByID(ctx, uid)
	if err != nil {
		return err
	}
	if bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.Password)) != nil {
		return errcode.ErrBadRequestParams.New("密码认证错误！")
	}
	user.Password, err = bcrypt.GenerateFromPassword([]byte(req.NewPassword), bcrypt.DefaultCost)
	if err != nil {
		return
	}
	user.IsDefaultPwd = constant.No
	return s.userRepo.Update(ctx, user, "password", "is_default_pwd")
}

//
//func (s *sysUserService) GetMenusByUid(ctx context.Context, uid int64) (userMenus *v1.UserMenus, err error) {
//	if uid == 0 {
//		return nil, errcode.ErrNotFound
//	}
//	userMenus = &v1.UserMenus{
//		MenuList:    make([]*m.SysMenu, 0),
//		Permissions: make([]string, 0),
//	}
//	//超级管理员
//	if uid == constant.SuperAdmin {
//		userMenus.MenuList, userMenus.Permissions, err = NewSysMenuService().GetTreeListByIds(ctx, nil, true)
//		return
//	}
//	user := &models.SysUser{}
//	err = facades.Orm.Query().Where("uid = ?", uid).First(&user)
//	if err != nil {
//		return
//	}
//	if user.RoleId != 0 {
//		var roleModel *models.SysRole
//		roleModel, err = NewSysRoleService().Detail(ctx, user.RoleId)
//		if err != nil {
//			err = nil
//			return
//		}
//		ids := rolem.MenuIds
//		menuService := NewSysMenuService()
//		userMenus.MenuList, userMenus.Permissions, err = menuService.GetTreeListByIds(ctx, ids, true)
//	}
//	return
//
//	user, err := s.userRepo.GetByID(ctx, uid)
//	if err != nil {
//		return nil, err
//	}
//
//	return nil, nil
//}
